/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package org.simba.utils.tree;

import java.util.Collection;
import java.util.HashMap;
import java.util.TreeSet;

/**
 *
 * @author ngonga
 */
public class Tree implements Comparable {

    HashMap<String, Node> nodes;
    //maps child to parent
    HashMap<String, HashMap<String, String>> edges;
    WordScore ws;
    
    public Tree() {
        nodes = new HashMap<String, Node>();
        edges = new HashMap<String, HashMap<String, String>>();
    }

    public Tree(String SentimentFile)
    {
        ws = new WordScore();
        //ws.loadSentiments(SentimentFile);
    }

    public TreeSet<Double> getModifiers(String s)
    {
        String edge;
        TreeSet<Double> result = new TreeSet<Double>();
        for(String child: edges.keySet())
        {
            for(String parent: edges.get(child).keySet())
            {
                edge = edges.get(child).get(parent);
                if(parent.startsWith(s) && (edge.contains("mod")||edge.contains("adj")))
                {
                    System.out.println("Modifier: "+child);
                    result.add(1+ws.getScore(child));
                }
                if(child.startsWith(s) && edge.contains("conj_negcc"))
                {
                    result.add(-1.0);
                }
                //else System.out.println(child + " " + parent + " " + edge);
            }
        }
        return result;
    }
    @Override
    public String toString() {
        StringBuffer b = new StringBuffer();
        for (String child : edges.keySet()) {
            for (String parent : edges.get(child).keySet()) {
                b.append(child + " -> " + edges.get(child).get(parent) + " -> " + parent + "\n");
            }
        }
        return b.toString();
    }

    public void addNode(String s) {
        if (!nodes.containsKey(s)) {
            Node n = new Node(s);
            nodes.put(s, n);
        }
    }

    public Node getNode(String s) {
        return nodes.get(s);
    }

    /** Gets all nodes such that their label starts with s
     * 
     * @param s Input String
     * @return Set of nodes
     */
    public TreeSet<Node> getMatchingNodes(String s) {
        TreeSet<Node> t = new TreeSet<Node>();
        for (String label : nodes.keySet()) {
            if (label.startsWith(s)) {
                t.add(nodes.get(label));
                System.out.println(nodes.get(label));
            }
        }
        return t;
    }

    public TreeSet<Node> getObjectVerb(Node child) {
        TreeSet<Node> verbs = new TreeSet<Node>();        
        if (edges.containsKey(child.label)) {
            HashMap<String, String> parents = edges.get(child.label);
            //System.out.println(parents);
            for (String parent : parents.keySet()) {
                if (edges.get(child.label).get(parent).startsWith("dobj") || 
                        edges.get(child.label).get(parent).startsWith("nsubj")) {
                    verbs.add(getNode(parent));
                } else {
                    verbs.addAll(getObjectVerb(getNode(parent)));
                }
            }
        }
        return verbs;
    }
    
    /**
     * Fetch all verbs of which "child" is the subject
     * @param child
     * @return 
     */
    public TreeSet<Node> getSubjectVerb(Node child) {
        TreeSet<Node> verbs = new TreeSet<Node>();        
        if (edges.containsKey(child.label)) {
            HashMap<String, String> parents = edges.get(child.label);
            //System.out.println(parents);
            for (String parent : parents.keySet()) {
                if (edges.get(child.label).get(parent).startsWith("nsubj")) {
                    verbs.add(getNode(parent));
                } else {
                    verbs.addAll(getObjectVerb(getNode(parent)));
                }
            }
        }
        return verbs;
    }

    public TreeSet<Node> getObjectVerbs(String s) {
        TreeSet<Node> result = new TreeSet<Node>();
        TreeSet<Node> mappingNodes = getMatchingNodes(s);
        TreeSet<Node> verbs;
        if (!mappingNodes.isEmpty()) {
            for (Node n : mappingNodes) {
                verbs = getObjectVerb(n);
                //System.out.println(verbs +" "+s);
                if (verbs != null) {
                    if(!verbs.isEmpty()) result.addAll(verbs);
                }
            }
        }
        return result;
    }

    public TreeSet<Node> getSubjectVerbs(String s) {
        TreeSet<Node> result = new TreeSet<Node>();
        TreeSet<Node> mappingNodes = getMatchingNodes(s);
        TreeSet<Node> verbs;
        if (!mappingNodes.isEmpty()) {
            for (Node n : mappingNodes) {
                verbs = getSubjectVerb(n);
                //System.out.println(verbs +" "+s);
                if (verbs != null) {
                    if(!verbs.isEmpty()) result.addAll(verbs);
                }
            }
        }
        return result;
    }
    
    public double getSentiment(String word, String position)
    {
        TreeSet<Node> subjectVerbs = getSubjectVerbs(word);
        TreeSet<Node> objectVerbs = getObjectVerbs(word);
        double score;
        if(objectVerbs.isEmpty() && subjectVerbs.isEmpty()) 
        {
            TreeSet<Double> modifiers = getModifiers(word);
            score = ws.getScore(word);
            for(double d: modifiers)
            {
                score = score*d;
            }
        }
        else
        {
            score = 0;
            for(Node verb: subjectVerbs)
            {
                score = score + getSentiment(verb.label, "subject");
            }
            
            for(Node verb: objectVerbs)
            {
                score = score + getSentiment(verb.label, "object");
            }
            
            TreeSet<Double> modifiers = getModifiers(word);
            for(double d: modifiers)
            {
                score = score*d;
            }            
        }
        return score;
    }
    public int getDistance(Node n1, Node n2) {
        return n1.getDistanceFrom(n2);
    }

    public Collection<Node> getElements() {
        return nodes.values();
    }

    public void addEdge(String parent, String child) {
        addEdge(parent, child, "");
    }

    public void addEdge(String parent, String child, String type) {
        //add parental information to nodes
        if (!nodes.containsKey(parent)) {
            nodes.put(parent, new Node(parent));
        }
        if (!nodes.containsKey(child)) {
            nodes.put(child, new Node(child));
        }
        nodes.get(child).parent = getNode(parent);

        //add same info to edges, duplicate I know
        if (!edges.containsKey(child)) {
            edges.put(child, new HashMap<String, String>());
        }
        edges.get(child).put(parent, type);
    }

    public Node getElement(String label, int foxIndex, String input) {
        String s = input.substring(0, foxIndex);
        String split[] = s.split(" ");
        if (nodes.containsKey(label + "-" + (split.length + 1))) {
            return nodes.get(label + "-" + (split.length + 1));
        } else {
            return null;
        }
    }

    @Override
    public int compareTo(Object o) {
        return 1;
    }
}
